#include <iostream>
#include <cstdio>
#include <signal.h>
#include <unistd.h>

using namespace std;

void CatchSig(int signum)
{
    cout << "捕获了一个信号：" << signum << endl;
}

void ShowPending(const sigset_t *ppset)
{
    for (int i = 1; i <= 31; ++i)
    {
        if (sigismember(ppset, i))
            cout << "1";
        else
            cout << "0";
    }

    cout << endl;
}

// 测试一：尝试捕捉[1,31]号，所有的普通信号
void test1()
{
    for (int i = 1; i <= 31; ++i)
    {
        signal(i, CatchSig);
    }
    while (1)
        ;
}

// 测试二：先阻塞2号信号，再解除阻塞，打印观察pending信号集
void test2()
{
    // 需要捕捉2号信号，否则解除后进程会立即退出。
    signal(2, CatchSig);
    // 定义信号集对象
    sigset_t bset, obset, pset;
    // 初始化信号集对象
    sigemptyset(&bset);
    sigemptyset(&bset);
    sigemptyset(&bset);
    // 将要进行屏蔽的信号添加到bset
    sigaddset(&bset, SIGINT);
    // 阻塞bset信号集[默认情况进程不会对任何信号进行block]
    cout << "阻塞2号信号！" << endl;
    sigprocmask(SIG_BLOCK, &bset, &obset);
    int cnt = 0;

    // 打印观察pending信号集
    while (true)
    {
        // 获取当前进程的pending信号集
        sigpending(&pset);
        // 显示pending信号集中的没有被递达的信号
        ShowPending(&pset);
        sleep(1);
        ++cnt;
        // 10秒后解除阻塞
        if (cnt == 10)
        {
            // 默认情况下，解除对于2号信号的block的时候，确实会进行递达
            // 但是2号信号的默认处理动作是终止进程！
            // 需要对2号信号进行捕捉
            cout << "解除阻塞2号信号！" << endl;
            sigprocmask(SIG_SETMASK, &obset, nullptr);
        }
    }
}

// 测试三：尝试阻塞[1,31]号，所有的普通信号
void test3()
{
    sigset_t bset, pset;
    // 初始化信号集对象将所有位置1，阻塞所有信号
    sigfillset(&bset);
    cout << "阻塞所有信号！" << endl;
    sigprocmask(SIG_BLOCK, &bset, nullptr);
    while (true)
    {
        sigpending(&pset);
        ShowPending(&pset);
        sleep(1);
    }
}

int main()
{
    cout << "pid: " << getpid() << endl;
    test3();
    return 0;
}